package com.gonsin.gview.logic.services.data;

import com.gonsin.gview.annotations.GContext;
import com.gonsin.gview.annotations.actions.GSession;
import com.gonsin.base.GPageRequest;
import com.gonsin.gview.logic.exceptions.BaseGViewException;
import com.gonsin.gview.logic.model.DataRequest;
import com.gonsin.gview.logic.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.springframework.util.NumberUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;

/**
 * 表格数据获取的代理类
 */
@Slf4j
public class DelegateListDataPicker extends GDataManager {

    private Object delegateService;

    private GContext context;

    private String dataId;

    private Method sourceMethod;

    public DelegateListDataPicker(GContext context, String dataId, Object delegateService, Method sourceMethod) {
        super(DelegateListDataPicker.class.getName(), sourceMethod.toString());
        this.delegateService = delegateService;
        this.sourceMethod = sourceMethod;
        this.dataId = dataId;
        this.context = context;
        if (!Modifier.isPublic(sourceMethod.getDeclaringClass().getModifiers())) {
            sourceMethod.setAccessible(true);
        }
        // 检查方式是否为public
        Class returnClass = sourceMethod.getReturnType();
        if(!List.class.isAssignableFrom(returnClass)){
            throw new BaseGViewException(String.format("【%s】中@GListData 或 @GTreeData 的数据源必须返回List", context.getViewName()));
        }
    }

    @Override
    public Object generalData(HttpServletRequest request, HttpServletResponse response, DataRequest dataRequest) throws Throwable {

        Map<String, Object> props = dataRequest.getProps();
        if(dataRequest.getProps() == null){
            props = new HashMap<>();
        }
//        List<KeyValue> kvs = dataRequest.getProps();
//        if(!CollectionUtils.isEmpty(kvs)){
//            kvs.forEach(kv -> {
//                props.put(kv.getKey(), kv.getValue());
//            });
//        }

//        Enumeration<String> names = request.getParameterNames();

        // 将请求参数组成一个map
//        Map<String, Object> params = new HashMap<>();
////        while(names.hasMoreElements()){
////            String key = names.nextElement();
////            String value = request.getParameter(key);
////            params.put(key, value);
////        }
//        params.putAll(props);


        int count = sourceMethod.getParameterCount();
        Object[] paramsArray = new Object[count];
//        sourceMethod.getParameterTypes();
        sourceMethod.getGenericParameterTypes();
        for(int i = 0; i < count; i++){
            Class p = sourceMethod.getParameterTypes()[i];
            if(HttpSession.class.isAssignableFrom(p)){
                paramsArray[i] = request.getSession();
                continue;
            }

            if(HttpServletRequest.class.isAssignableFrom(p)){
                paramsArray[i] = request;
                continue;
            }

            if(HttpServletResponse.class.isAssignableFrom(p)){
                paramsArray[i] = response;
                continue;
            }

            if(GPageRequest.class.isAssignableFrom(p)){
                GPageRequest pageRequest = new GPageRequest();
                pageRequest.setPage(NumberUtils.parseNumber(Objects.toString(props.get("page")), Integer.class));
                pageRequest.setCount(NumberUtils.parseNumber(Objects.toString(props.get("count")), Integer.class));
                if(props.containsKey("sort")){
                    pageRequest.setSort(Objects.toString(props.get("sort")));
                }
                paramsArray[i] = pageRequest;
                continue;
            }

            // 如果是基本数据类型
            if(ValueUtils.isWrapClass(p)){
                String name = ValueUtils.getParamName(sourceMethod, i);
                GSession gSession = ValueUtils.getSessionAnnotation(sourceMethod, i);
                if(gSession != null){
                    String sessionName = gSession.value();
                    Object value = ValueUtils.parseValue(request.getSession().getAttribute(sessionName), p);
                    paramsArray[i] = value;
                } else {
                    Object value = ValueUtils.parseValue(props.get(name), p);
                    paramsArray[i] = value;
                }

                continue;
            }


            // 创建类转存表单
            Object searchPo = null;
            try {
                searchPo = Class.forName(p.getTypeName()).newInstance();
            } catch (Exception e) {
                log.error(e.toString(), e);
                throw new BaseGViewException(String.format("无法创建类【%s】", p.getName()));
            }
//            Map<String, Class> fieldClassMap = new HashMap<>();
            Map<String, Object> searchPoMap = new HashMap<>();
            Field[] allFields = p.getDeclaredFields();
            for(Field field : allFields){
//                fieldClassMap.put(field.getName(), field.getGenericType());
                try {
                    searchPoMap.put(field.getName(), ValueUtils.parseValue(props.get(field.getName()), field.getGenericType()));
                } catch (Exception ex) {
                    log.warn(ex.toString(), ex);
                    log.warn("设置参数【{}】，设置的内容为“{}“", field.getName(), props.get(field.getName()));
                }
            }
            try {
                BeanUtilsBean utils = BeanUtilsBean.getInstance();
                utils.getConvertUtils().register(new MyDateConverter(), java.util.Date.class);
                utils.getConvertUtils().register(new MyBooleanConverter(), Boolean.class);
                utils.getConvertUtils().register(new MyIntegerConverter(), Integer.class);
                utils.getConvertUtils().register(new MyLongConverter(), Long.class);
                utils.getConvertUtils().register(new MyShortConverter(), Short.class);
                utils.getConvertUtils().register(new MyByteConverter(), Byte.class);
                utils.getConvertUtils().register(new MyDoubleConverter(), Double.class);
                utils.getConvertUtils().register(new MyFloatConverter(), Float.class);
                utils.getConvertUtils().register(new MyCharConverter(), Character.class);
                utils.populate(searchPo, searchPoMap);
                paramsArray[i] = searchPo;
                continue;
            } catch (Exception e) {
                log.error(e.toString() ,e);
                throw new BaseGViewException(String.format("无法创建类【%s】", p.getTypeName()));
            }
        }

        try {
            return sourceMethod.invoke(delegateService, paramsArray);
        } catch (Exception e) {
            if(e instanceof InvocationTargetException){
                throw ((InvocationTargetException) e).getTargetException();
            }
            throw e;
//            log.error(e.toString(), e);
//            throw new BaseGViewException(String.format("执行方法【%s】失败，可能是因为该方法不是public", sourceMethod.getName()));
        }

    }
}
